package edu.gmu.hodum.sei.bluetooth;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;

public class SerialIntent implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 8752553176223162573L;
	private final String action;
	private final Set<String> categories;
	private final String component;
	private final String dataString;
	private final int flags;
	//private final SerialIntent selector; not impl'd in Android 2.3.3
	private final String packageName;
	private final String type;
	private final String sourceBounds;

	private final Map<String, Boolean[]> booleanArrayExtras = new HashMap<String, Boolean[]>();
	private final Map<String, Boolean> booleanExtras = new HashMap<String, Boolean>();
	//bundle extra not impl'd
	private final Map<String, Byte[]> byteArrayExtras = new HashMap<String, Byte[]>();
	private final Map<String, Byte> byteExtras = new HashMap<String, Byte>();
	private final Map<String, Character[]> charArrayExtras = new HashMap<String, Character[]>();
	private final Map<String, Character> charExtras = new HashMap<String, Character>();
	private final Map<String, CharSequence[]> charSeqArrayExtras = new HashMap<String, CharSequence[]>();
	private final Map<String, CharSequence> charSeqExtras = new HashMap<String, CharSequence>();
	private final Map<String, ArrayList<CharSequence>> charSeqArrayListExtras = new HashMap<String, ArrayList<CharSequence>>();
	private final Map<String, Double[]> doubleArrayExtras = new HashMap<String, Double[]>();
	private final Map<String, Double> doubleExtras = new HashMap<String, Double>();
	private final Map<String, Float[]> floatArrayExtras = new HashMap<String, Float[]>();
	private final Map<String, Float> floatExtras = new HashMap<String, Float>();
	private final Map<String, Integer[]> intArrayExtras = new HashMap<String, Integer[]>();
	private final Map<String, Integer> intExtras = new HashMap<String, Integer>();
	private final Map<String, ArrayList<Integer>> intArrayListExtras = new HashMap<String, ArrayList<Integer>>();
	private final Map<String, Long[]> longArrayExtras = new HashMap<String, Long[]>();
	private final Map<String, Long> longExtras = new HashMap<String, Long>();
	//parcelable extras not impl'd
	private final Map<String, Serializable> serialExtras = new HashMap<String, Serializable>();
	private final Map<String, Short[]> shortArrayExtras = new HashMap<String, Short[]>();
	private final Map<String, Short> shortExtras = new HashMap<String, Short>();
	private final Map<String, String[]> stringArrayExtras = new HashMap<String, String[]>();
	private final Map<String, ArrayList<String>> stringArrayListExtras = new HashMap<String, ArrayList<String>>();
	private final Map<String, String> stringExtras = new HashMap<String, String>();


	@SuppressWarnings("unchecked")
	SerialIntent(Intent intent){
		this.action = intent.getAction();
		this.categories = intent.getCategories();
		this.dataString = intent.getDataString();
		if (intent.getComponent()!=null){
			this.component = intent.getComponent().flattenToString();
		}
		else {
			this.component = null;
		}
		this.flags = intent.getFlags();
		this.packageName = intent.getPackage();
		this.type = intent.getType();
		if (intent.getSourceBounds()!=null){
			this.sourceBounds = intent.getSourceBounds().flattenToString();
		}
		else {
			this.sourceBounds = null;
		}

		Bundle extras = intent.getExtras();
		if (extras!=null){
			Set<String> keySet = extras.keySet();
			Object o;

			for (String key: keySet){
				o = extras.get(key);

				if (o instanceof Boolean[]){
					booleanArrayExtras.put(key, (Boolean[])o);
				}
				else if (o instanceof Boolean){
					booleanExtras.put(key, (Boolean)o);
				}
				else if (o instanceof Byte[]){
					byteArrayExtras.put(key, (Byte[])o);
				}
				else if (o instanceof Byte){
					byteExtras.put(key, (Byte)o);
				}
				else if (o instanceof Character[]){
					charArrayExtras.put(key, (Character[])o);
				}
				else if (o instanceof Character){
					charExtras.put(key, (Character)o);
				}
				//String must come before CharSequence
				else if (o instanceof String[]){
					stringArrayExtras.put(key, (String[])o);
				}
				else if (o instanceof String){
					stringExtras.put(key, (String)o);
				}
				else if (o instanceof CharSequence[]){
					charSeqArrayExtras.put(key, (CharSequence[])o);
				}
				else if (o instanceof CharSequence){
					charSeqExtras.put(key, (CharSequence)o);
				}
				//handles all of the arraylists in the intent
				else if (o instanceof ArrayList){
					ArrayList<?> arraylist = (ArrayList<?>)o;
					try{
						if(arraylist!= null && arraylist.size()>0){
							if (arraylist.get(0) instanceof String){
								stringArrayListExtras.put(key, (ArrayList<String>)o);
							}
							else if (arraylist.get(0) instanceof CharSequence){
								charSeqArrayListExtras.put(key, (ArrayList<CharSequence>)o);
							}
							else if (arraylist.get(0) instanceof Integer){
								intArrayListExtras.put(key, (ArrayList<Integer>)o);
							}
						}
					}catch(ClassCastException e){
						System.out.println("SerialIntent ClassCastException");
						//do nothing
					}

				}
				else if (o instanceof Double[]){
					doubleArrayExtras.put(key, (Double[])o);
				}
				else if (o instanceof Double){
					doubleExtras.put(key, (Double)o);
				}
				else if (o instanceof Float[]){
					floatArrayExtras.put(key, (Float[])o);
				}
				else if (o instanceof Float){
					floatExtras.put(key, (Float)o);
				}
				else if (o instanceof Integer[]){
					intArrayExtras.put(key, (Integer[])o);
				}
				else if (o instanceof Integer){
					intExtras.put(key, (Integer)o);
				}
				else if (o instanceof Long[]){
					longArrayExtras.put(key, (Long[])o);
				}
				else if (o instanceof Long){
					longExtras.put(key, (Long)o);
				}
				else if (o instanceof Short[]){
					shortArrayExtras.put(key, (Short[])o);
				}
				else if (o instanceof Short){
					shortExtras.put(key, (Short)o);
				}

				//Serializable must be last
				else if (o instanceof Serializable){
					serialExtras.put(key, (Serializable)o);
				}
			}
		}
	}

	public Intent getIntent(){
		Intent intent = new Intent(action);
		if (categories!=null){
			for (String cat : categories){
				intent.addCategory(cat);
			}
		}
		if (component!=null){
			intent.setComponent(ComponentName.unflattenFromString(component));	
		}
		if (sourceBounds!=null){
			intent.setSourceBounds(Rect.unflattenFromString(sourceBounds));	
		}
		if(dataString!=null){
			intent.setData(Uri.parse(dataString));
		}
		intent.setFlags(flags);
		intent.setPackage(packageName);
		intent.setType(type);

		Set<String> keySet;

		keySet = booleanArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, booleanArrayExtras.get(key));
		}
		keySet = booleanExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, booleanExtras.get(key));
		}
		keySet = byteArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, byteArrayExtras.get(key));
		}
		keySet = byteExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, byteExtras.get(key));
		}
		keySet = charArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, charArrayExtras.get(key));
		}
		keySet = charExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, charExtras.get(key));
		}
		keySet = charSeqArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, charSeqArrayExtras.get(key));
		}
		keySet = charSeqExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, charSeqExtras.get(key));
		}
		keySet = charSeqArrayListExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, charSeqArrayListExtras.get(key));
		}
		keySet = doubleArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, doubleArrayExtras.get(key));
		}
		keySet = doubleExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, doubleExtras.get(key));
		}
		keySet = floatArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, floatArrayExtras.get(key));
		}
		keySet = floatExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, floatExtras.get(key));
		}
		keySet = intArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, intArrayExtras.get(key));
		}
		keySet = intExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, intExtras.get(key));
		}
		keySet = intArrayListExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, intArrayListExtras.get(key));
		}
		keySet = longArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, longArrayExtras.get(key));
		}
		keySet = longExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, longExtras.get(key));
		}
		keySet = serialExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, serialExtras.get(key));
		}
		keySet = shortArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, shortArrayExtras.get(key));
		}
		keySet = shortExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, shortExtras.get(key));
		}
		keySet = stringArrayExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, stringArrayExtras.get(key));
		}
		keySet = stringArrayListExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, stringArrayListExtras.get(key));
		}
		keySet = stringExtras.keySet();
		for(String key: keySet){
			intent.putExtra(key, stringExtras.get(key));
		}
		return intent;
	}
}
